package edu.ksu.cis.projects.bogor;

import edu.ksu.cis.projects.bogor.ast.checker.Checker;
import edu.ksu.cis.projects.bogor.ast.transform.BIRUnitSystemTransformer;
import edu.ksu.cis.projects.bogor.ast.transform.HighToLowBIRCompiler;
import edu.ksu.cis.projects.bogor.ast.transform.ISystemTransformer;
import edu.ksu.cis.projects.bogor.ast.transform.ITransformSystemResult;
import edu.ksu.cis.projects.bogor.module.AbstractProgressManager;
import edu.ksu.cis.projects.bogor.module.DefaultMessageStore;
import edu.ksu.cis.projects.bogor.module.IMessageStore;
import edu.ksu.cis.projects.bogor.module.IProgressManager;
import edu.ksu.cis.projects.bogor.module.ISearcher;
import edu.ksu.cis.projects.bogor.parser.BogorParser;
import edu.ksu.cis.projects.bogor.symboltable.SymbolTable;
import edu.ksu.cis.projects.bogor.util.FileMessage;
import gnu.getopt.Getopt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Bogor
{
  public static final String TYPE_CHECKING_ONLY_ID = "typeCheckingOnly";
  public static final String LOGGING_ID = "logging";
  private static final Level loggingOffLevel;
  private static final Level loggingOnLevel;
  private static final String ERROR_OUTPUT_PREFIX = "(E)";
  private static final String WARNING_OUTPUT_PREFIX = "(W)";

  public static SymbolTable getSymbolTable(IBogorConfiguration bc, Properties configuration, String filename, PrintWriter pw, boolean applyTransformers)
    throws FileNotFoundException
  {
    return getSymbolTable(bc, configuration, filename, new FileReader(filename), pw, applyTransformers);
  }

  public static SymbolTable getSymbolTable(IBogorConfiguration bc, Properties configuration, String sourceFilename, edu.ksu.cis.projects.bogor.ast.System compilationUnit, List<String> parserErrors, PrintWriter pw, boolean applyTransformers)
  {
    try
    {
      SymbolTable symbolTable = new SymbolTable(sourceFilename, compilationUnit);

      for (String pe : parserErrors)
      {
        symbolTable.getErrors().add(FileMessage.buildMessage(pe, new String[0]));
      }

      Checker checker = new Checker();
      checker.check(symbolTable);

      ArrayList errors = new ArrayList();
      ISystemTransformer[] transformers = bc.getSystemTransformers(configuration, errors);

      if (errors.size() > 0)
      {
        symbolTable.getAllErrors().addAll(errors);
        symbolTable.setError(true);
      }

      if (!(symbolTable.getError()))
      {
        ITransformSystemResult itsr = new BIRUnitSystemTransformer().transformSystem(compilationUnit, configuration, bc, symbolTable, !(applyTransformers));

        symbolTable.getWarnings().addAll(itsr.getMessages().getWarnings());

        if (itsr.getMessages().getErrorCount() > 0)
        {
          symbolTable.getErrors().addAll(itsr.getMessages().getErrors());

          symbolTable.setError(true);
        }
        else if (itsr.wasSystemAltered())
        {
          List oldWarnings = symbolTable.getWarnings();

          symbolTable = new SymbolTable(sourceFilename, compilationUnit);

          checker = new Checker();
          checker.check(symbolTable);

          symbolTable.getWarnings().addAll(oldWarnings);
        }

      }

      if (!(symbolTable.getError()))
      {
        ITransformSystemResult itsr = new HighToLowBIRCompiler().transformSystem(compilationUnit, configuration, bc, symbolTable, !(applyTransformers));

        symbolTable.getWarnings().addAll(itsr.getMessages().getWarnings());

        if (itsr.getMessages().getErrorCount() > 0)
        {
          symbolTable.getErrors().addAll(itsr.getMessages().getErrors());

          symbolTable.setError(true);
        }
        else if (itsr.wasSystemAltered())
        {
          List oldWarnings = symbolTable.getWarnings();

          symbolTable = new SymbolTable(sourceFilename, compilationUnit);

          checker = new Checker();
          checker.check(symbolTable);

          symbolTable.getWarnings().addAll(oldWarnings);
        }
      }

      int i = 0;
      for (; (i < transformers.length) && (!(symbolTable.getError())); ++i)
      {
        ITransformSystemResult itsr = transformers[i].transformSystem(compilationUnit, configuration, bc, symbolTable, !(applyTransformers));

        symbolTable.getWarnings().addAll(itsr.getMessages().getWarnings());

        if (itsr.getMessages().getErrorCount() > 0)
        {
          symbolTable.getErrors().addAll(itsr.getMessages().getErrors());

          symbolTable.setError(true);
        } else {
          if (!(itsr.wasSystemAltered()))
            continue;
          List oldWarnings = symbolTable.getWarnings();

          symbolTable = new SymbolTable(sourceFilename, compilationUnit);

          checker = new Checker();
          checker.check(symbolTable);

          symbolTable.getWarnings().addAll(oldWarnings);
        }
      }

      return symbolTable;
    }
    catch (Exception e)
    {
      pw.println(e.getMessage());
    }
    return null;
  }

  public static SymbolTable getSymbolTable(IBogorConfiguration bc, Properties configuration, String sourceFilename, Reader source, PrintWriter pw, boolean applyTransformers)
  {
    edu.ksu.cis.projects.bogor.ast.System compilationUnit;
    List parserErrors;
    try
    {
      BogorParser bp = new BogorParser(source);
      compilationUnit = bp.System();
      source.close();
      parserErrors = bp.getErrors();
    }
    catch (Exception e)
    {
      pw.println(e.getMessage());

      return null;
    }

    return getSymbolTable(bc, configuration, sourceFilename, compilationUnit, parserErrors, pw, applyTransformers);
  }

  public static void main(String[] args)
    throws Exception
  {
    PrintWriter pw = new PrintWriter(java.lang.System.out);

    printCopyright(pw);

    CommandLineSwitches switches = parseCommandLineOptions(args, pw);

    if (switches.shouldAbort)
    {
      return;
    }

    boolean abort = false;

    Map externalObjectMap = null;

    if (!(switches.configFile.canRead()))
    {
      pw.printf("Can't open configuration file \"%s\"\n", new Object[] { switches.configFile });

      pw.flush();

      abort = true;
    }

    if (!(switches.modelFile.canRead()))
    {
      pw.printf("Can't open model file \"%s\"\n", new Object[] { switches.modelFile });
      pw.flush();

      abort = true;
    }

    if ((switches.externalObjectMapFile != null) && (!(switches.externalObjectMapFile.canRead())))
    {
      pw.printf("Can't open external input objects file \"%s\"\n", new Object[] { switches.externalObjectMapFile });

      pw.flush();

      abort = true;
    }
    else if (switches.externalObjectMapFile != null)
    {
      try
      {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(switches.externalObjectMapFile));

        externalObjectMap = (Map)ois.readObject();
      }
      catch (Exception x)
      {
        pw.printf("Error deserializing external object input map \"%s\":\n", new Object[] { switches.externalObjectMapFile });

        x.printStackTrace(pw);
        pw.flush();

        abort = true;
      }

    }

    if (abort)
    {
      return;
    }

    Properties configuration = new Properties();
    FileInputStream fis = new FileInputStream(switches.configFile);
    configuration.load(fis);

    IBogorConfiguration bc = new DefaultBogorConfiguration();

    SymbolTable symbolTable = getSymbolTable(bc, configuration, switches.modelFile.getAbsolutePath(), pw, true);

    if ((symbolTable == null) || (symbolTable.getError()))
    {
      if (symbolTable != null)
      {
        printErrors(symbolTable.getAllErrors(), pw, "(E)");
      }

      pw.flush();

      return;
    }

    modelCheck(symbolTable, pw, new AbstractProgressManager()
    {
      PrintWriter pw;

      public void update(long transitions, int states, int matchedStates, long currentDepth, long maxDepth, int errors, long time, boolean isDone)
      {
        super.update(transitions, states, matchedStates, currentDepth, maxDepth, errors, time, isDone);

        StringBuffer sb = new StringBuffer("Transitions: ");
        sb.append(transitions);
        sb.append(", States: ");
        sb.append(states);
        sb.append(", Matched States: ");
        sb.append(matchedStates);
        sb.append(", Max Depth: ");
        sb.append(maxDepth);
        sb.append(", Errors found: ");
        sb.append(errors);
        this.pw.println(sb.toString());
        this.pw.flush();
      }

      public IMessageStore connect(IBogorConfiguration bc)
      {
        this.pw = bc.getPrintWriter();

        return new DefaultMessageStore();
      }

      public void dispose()
      {
        this.pw = null;
      }
    }
    , bc, configuration, (externalObjectMap == null) ? new HashMap() : externalObjectMap);

    fis.close();
  }

  public static IMessageStore modelCheck(String sourceFilename, Reader source, PrintWriter pw, IProgressManager pm, IBogorConfiguration bc, Properties configuration, Map<String, Object> externalObjectMap)
  {
    assert (sourceFilename != null);
    assert (source != null);
    assert (pw != null);
    assert (bc != null);

    SymbolTable symbolTable = getSymbolTable(bc, configuration, sourceFilename, source, pw, true);

    if ((symbolTable == null) || (symbolTable.getError()))
    {
      if (symbolTable != null)
      {
        printErrors(symbolTable.getAllErrors(), pw, "(E)");
      }

      pw.flush();

      return new DefaultMessageStore();
    }

    return modelCheck(symbolTable, pw, pm, bc, configuration, externalObjectMap);
  }

  public IMessageStore modelCheck(String filename, PrintWriter pw, IProgressManager pm, IBogorConfiguration bc, Properties configuration, Map<String, Object> externalObjectMap)
    throws FileNotFoundException
  {
    assert (filename != null);
    assert (pw != null);
    assert (bc != null);

    SymbolTable symbolTable = getSymbolTable(bc, configuration, filename, pw, false);

    if ((symbolTable == null) || (symbolTable.getError()))
    {
      if (symbolTable != null)
      {
        printErrors(symbolTable.getAllErrors(), pw, "(E)");
      }

      pw.flush();

      return new DefaultMessageStore();
    }

    return modelCheck(symbolTable, pw, pm, bc, configuration, externalObjectMap);
  }

  public static IMessageStore modelCheck(SymbolTable symbolTable, PrintWriter pw, IProgressManager pm, IBogorConfiguration bc, Properties c, Map<String, Object> externalObjectMap)
  {
    String value = c.getProperty("typeCheckingOnly");

    if ((value != null) && (Boolean.valueOf(value).booleanValue()))
    {
      return new DefaultMessageStore();
    }

    configureLogging(c);

    IMessageStore messages = bc.initialize(symbolTable, pm, pw, c, externalObjectMap);

    int size = messages.getErrorCount();

    if (size > 0)
    {
      pw.println();
      pw.println("Errors when initializing:");

      for (int i = 0; i < size; ++i)
      {
        StringBuffer sb = new StringBuffer("- ");
        FileMessage fm = messages.getError(i);

        if (fm.hasLocation())
        {
          sb.append("[Line " + fm.getLine() + ", Column " + fm.getColumn() + "] ");
        }

        pw.println(sb.append(fm.getText()));
      }

      pw.println();
      pw.flush();
    }
    else
    {
      printErrors(messages.getWarnings(), pw, "(W)");

      bc.getSearcher().initialize();
      bc.getSearcher().search();
    }

    bc.dispose();
    return messages;
  }

  public static void printCopyright(PrintWriter pw)
  {
    pw.println("Bogor v.1.1 (build 1.1.20060525.0)");
    pw.println("(c) Copyright by Kansas State University");
    pw.println();
    pw.println("Web: http://bogor.projects.cis.ksu.edu");
    pw.println();
    pw.flush();
  }

  private static CommandLineSwitches parseCommandLineOptions(String[] args, PrintWriter pw)
  {
    File configFile = null;
    File modelFile = null;
    File externalObjectMapFile = null;

    boolean malformed = false;

    if ((args.length == 2) && (!(args[0].startsWith("-"))))
    {
      configFile = new File(args[0]);
      modelFile = new File(args[1]);
    }
    else
    {
      Getopt g = new Getopt("Bogor", args, "f:c:m:");
      g.setOpterr(false);

      HashSet errMsgs = new HashSet();

      int c;
	while ((c = g.getopt()) != -1)
      {
        
        switch (c)
        {
        case 102:
          if (modelFile != null)
          {
            errMsgs.add("Only one model file can be selected");
          }
          else
          {
            modelFile = new File(g.getOptarg());
          }
          break;
        case 99:
          if (configFile != null)
          {
            errMsgs.add("Only one configuration file can be selected");
          }
          else
          {
            configFile = new File(g.getOptarg());
          }
          break;
        case 109:
          if (externalObjectMapFile != null)
          {
            errMsgs.add("Only one external-object-map file can be selected");
          }
          else
          {
            externalObjectMapFile = new File(g.getOptarg());
          }
          break;
        case 58:
          errMsgs.add("Doh! You need an argument for option " + (char)g.getOptopt());

          break;
        case 63:
          errMsgs.add("The option '" + (char)g.getOptopt() + "' is not valid");
        }

      }

   /*   for (String s : errMsgs)
      {
        pw.println(s);
      }
*/
      if ((modelFile == null) || (configFile == null) || (errMsgs.size() > 0))
      {
        malformed = true;
      }
    }

    if (malformed)
    {
      pw.println("Usage: bogor <configuration-file> <input-file>");
      pw.println("           or");
      pw.println("       bogor -c <configuration-file>");
      pw.println("             -f <input-file>");
      pw.println("             [ -m <external-object-map-file>");
      pw.flush();
    }

    return new CommandLineSwitches(malformed, configFile, modelFile, externalObjectMapFile);
  }

  private static void configureLogging(Properties config)
  {
    Logger mainLogger = Logger.getLogger("bogor");
    boolean set = false;
    try
    {
      if (Boolean.valueOf(java.lang.System.getProperty("edu.ksu.cis.projects.bogor.logging")).booleanValue())
      {
        mainLogger.setLevel(loggingOnLevel);
        set = true;
      }

    }
    catch (Exception e)
    {
    }

    try
    {
      if (Boolean.valueOf(config.getProperty("logging")).booleanValue())
      {
        mainLogger.setLevel(loggingOnLevel);
        set = true;
      }

    }
    catch (Exception e)
    {
    }

    if (set)
      return;
    mainLogger.setLevel(loggingOffLevel);
  }

  private static void printErrors(Collection<FileMessage> errors, PrintWriter pw, String prefix)
  {
    for (FileMessage fm : errors)
    {
      StringBuilder sb = new StringBuilder(prefix);
      sb.append(' ');

      if (fm.hasLocation())
      {
        sb.append("[Line " + fm.getLine() + ", Column " + fm.getColumn() + "] ");
      }

      pw.println(sb.append(fm.getText()));
    }

    pw.flush();
  }

  static
  {
    loggingOffLevel = Level.SEVERE;

    loggingOnLevel = Level.ALL;
  }

  private static class CommandLineSwitches
  {
    public final File modelFile;
    public final File configFile;
    public final File externalObjectMapFile;
    public final boolean shouldAbort;

    public CommandLineSwitches(boolean abort, File configFile, File modelFile, File externalObjectMapFile)
    {
      this.modelFile = modelFile;
      this.configFile = configFile;
      this.externalObjectMapFile = externalObjectMapFile;
      this.shouldAbort = abort;
    }
  }
}

/* Location:           D:\tool\banderaCLI-1.0a4\lib\bogor\bogorCore.jar
 * Qualified Name:     edu.ksu.cis.projects.bogor.Bogor
 * Java Class Version: 5 (49.0)
 * JD-Core Version:    0.5.3
 */